﻿// (c) Copyright Max Kazarin.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.

/// <reference path='../Common/jquery-1.3.2.js' />
// <reference path='../Common/MicrosoftAjax.debug.js' />

Type.registerNamespace("jQueryNET.Controls");

jQueryNET.Controls.ComboBox = function jQueryNET$Controls$ComboBox(element) {
	/// <summary>
	/// This class implement ComboBox control
	/// </summary>
	/// <param name='element' type='Sys.UI.DomElement' domElement='true'>
	/// DOM element the control is associated with
	/// </param>

	jQueryNET.Controls.ComboBox.initializeBase(this, [element]);
	this._rootElement.removeAttr('disabled');

	this._rootElement
		.append('<input type="text" autocomplete="off" class="textarea"/><img class="trigger" src="<%=WebResource("jQueryNET.Common.Images.s.gif")%>">')
		.addClass("combobox");

	this._inputElement = this._rootElement.find('input')
	this._triggerElement = this._rootElement.find('img');

	this._comboListElement = this._rootElement
		.parent()
		.append('<div class="combobox_list"><div class="combobox_list_inner"></div></div>').find('div.combobox_list:last');

	this._onDocumentMouseDownHandler = Function.eventWraper(this, this._onDocumentMouseDown);

	this._onMouseOverHandler = Function.eventWraper(this, this._onMouseOver);
	this._onMouseOutHandler = Function.eventWraper(this, this._onMouseOut);
	this._onMouseDownHandler = Function.eventWraper(this, this._onMouseDown);
	this._onMouseUpHandler = Function.eventWraper(this, this._onMouseUp);
	this._onMouseClickHandler = Function.eventWraper(this, this._onMouseClick);

	this._onItemMouseOverHandler = Function.eventWraper(this, this._onItemMouseOver);
	this._onItemMouseOutHandler = Function.eventWraper(this, this._onItemMouseOut);
	this._onItemMouseClickHandler = Function.eventWraper(this, this._onItemMouseClick);

	this._refreshSynchronizer = Function.createSynchronizer(this, this.refresh);

}

jQueryNET.Controls.ComboBox.createElement = function(parent) {
	/// <summary>
	/// Static method for using on client-side. Create DOM element the control
	/// associated with
	/// </summary>
	/// <param name='parent' type='Sys.UI.DomElement' domElement='true'>
	/// Parent DOM element or jQuery selector
	/// </param>

	var element =
		$(parent)
			.append('<div></div>')
			.find('div:last');

	return element.get(0);
}

function jQueryNET$Controls$ComboBox$initialize() {
	/// <summary>
	/// Initialize the control
	/// </summary>

	jQueryNET.Controls.ComboBox.callBaseMethod(this, "initialize");

	this._comboListElement.addClass(this.get_theme());

	$(document)
		.bind('mousedown', this._onDocumentMouseDownHandler)

	this._triggerElement
		.hover(this._onMouseOverHandler, this._onMouseOutHandler)
		.bind('mousedown', this._onMouseDownHandler)
		.bind('mouseup', this._onMouseUpHandler)
		.bind('click', this._onMouseClickHandler);
}

function jQueryNET$Controls$ComboBox$dispose() {
	/// <summary>
	/// Dispose the control
	/// </summary>

	$(document)
		.unbind('mousedown', this._onDocumentMouseDownHandler);

	this._triggerElement
		.unbind('mousedown', this._onMouseDownHandler)
		.unbind('mouseup', this._onMouseUpHandler)
		.unbind('click', this._onMouseClickHandler);

	jQueryNET.Controls.ComboBox.callBaseMethod(this, "dispose");
}

function jQueryNET$Controls$ComboBox$set_theme(value) {
	jQueryNET.Controls.ComboBox.callBaseMethod(this, "set_theme", [value]);

	this._comboListElement.addClass(this._theme);
}

function jQueryNET$Controls$ComboBox$get_items() {
	/// <value type='String'>
	/// ComboBox list items
	/// </value>

	if (arguments.length !== 0) throw Error.parameterCount();
	return this._items;
}

function jQueryNET$Controls$ComboBox$set_items(value) {
	if (!Array.isInstanceOfType(value))
		value = Sys.Serialization.JavaScriptSerializer.deserialize(value);
		
	var e = Function._validateParams(arguments, [{ name: "value", type: Object, mayBeNull: true}]);
	if (e) throw e;

	if (this.get_isLoading())
		return;

	var innerComboListElement = this._comboListElement.children('div');

	// Remove old items from combobox list
	var itemsElement = innerComboListElement.children('div.combobox_list_item');
	if (itemsElement.size() > 0) {
		itemsElement
			.unbind('click', this._onItemMouseClickHandler);

		innerComboListElement.empty();
	}
	
	this._hasItems = (value != null && value.length > 0);

	if (!this._hasItems)
		return;
		
	this._items = value;

	Array.forEach(
		this._items,
		function(element, index, array) {
			innerComboListElement.append(
				'<div id="' + index +
				'" class="combobox_list_item">' + element.Text +
				'</div>');
		},
		this);

	innerComboListElement.children('div.combobox_list_item')
		.hover(this._onItemMouseOverHandler, this._onItemMouseOutHandler)
		.bind('click', this._onItemMouseClickHandler);
}

function jQueryNET$Controls$ComboBox$get_selectedItem() {
	/// <value type='String'>
	/// Selected items
	/// </value>

	if (arguments.length !== 0) throw Error.parameterCount();
	return this._selectedItem;
}

function jQueryNET$Controls$ComboBox$get_selectedIndex() {
	/// <value type='String'>
	/// Selected item index
	/// </value>

	if (arguments.length !== 0) throw Error.parameterCount();
	if (!this._hasItems) return -1;
	return this._selectedIndex;
}

function jQueryNET$Controls$ComboBox$set_selectedIndex(value) {
	var e = Function._validateParams(arguments, [{ name: "value", type: Number, mayBeNull: true}]);
	if (e) throw e;

	if (this.get_isLoading())
		return;

	if (value < 0)
		return;

	if (this._hasItems) {
		this._selectedItem = this._items[value];
		if (!this._selectedItem) {
			this._selectedIndex = -1;
			this._selectedItem = null;
			this._selectedValue = null;
			return;
		}

		this._selectedIndex = value;
		this._selectedValue = this._selectedItem.Value;
		this._selectedElement = this._comboListElement.find('div>div#' + value);
		this._inputElement.attr('value', this._selectedItem.Text);

		this.raiseSelectItemChange(this._selectedValue);
		return;
	}

	//this.refresh();
}

function jQueryNET$Controls$ComboBox$get_selectedValue() {
	/// <value type='String'>
	/// Selected item value
	/// </value>

	if (arguments.length !== 0) throw Error.parameterCount();
	var selectedItem = this.get_selectedItem();
	if (selectedItem != null)
		return this._selectedItem.Value;
	
	return null;
}

function jQueryNET$Controls$ComboBox$set_selectedValue(value) {
	var e = Function._validateParams(arguments, [{ name: "value", mayBeNull: false}]);
	if (e) throw e;

	if (value == "")
		return;

	if (this.get_isLoading())
		return;

	if (!this.get_isLoaded()) {
		Function.lock(this);
		this._refreshSynchronizer();
		return;
	}

	if (this._hasItems) {
		for (var index = 0; index < this._items.length; index++)
			if (this._items[index].Value == value) {
				this.set_selectedIndex(index);
				break;
			}

		//if (this.get_selectedIndex() != index)
		//	throw Error.argumentOutOfRange("value", value);

		return;
	}

	//this.refresh();
}

function jQueryNET$Controls$ComboBox$get_enabled() {
	/// <value type='String'>
	/// Enabled element state
	/// </value>

	if (arguments.length !== 0) throw Error.parameterCount();
	return this._enabled;
}

function jQueryNET$Controls$ComboBox$set_enabled(value) {
	var e = Function._validateParams(arguments, [{ name: "value", type: Boolean, mayBeNull: true}]);
	if (e) throw e;

	this._enabled = value;

	if (!value) {
		this._inputElement.attr("disabled", "disabled");
		this._rootElement.addClass('disabled');
	}
	else {
		this._inputElement.removeAttr("disabled");
		this._rootElement.removeClass('disabled');
	}
}

function jQueryNET$Controls$ComboBox$set_width(value) {
	jQueryNET.Controls.ComboBox.callBaseMethod(this, "set_width", [value]);

	var dwidth = this._inputElement.outerWidth() - this._inputElement.width();
	this._inputElement.width(this._rootElement.width() - this._triggerElement.width() - dwidth);
}

function jQueryNET$Controls$ComboBox$clear() {
	this.set_items([]);
	this._selectedIndex = -1;
	this._selectedItem = null;
	this._selectedValue = null;
	this._inputElement.removeAttr('value');
}

function jQueryNET$Controls$ComboBox$refresh() {
//    debugger;
	this.receiveData(null, false);
}

function jQueryNET$Controls$ComboBox$_showComboList() {
	/// <summary>
	/// Show combobox list
	/// </summary>

	if (!this._hasItems && this.get_dataSourceId() &&
		(this._dataSource == null || !this._dataSource.get_isLoaded())) {
		Function.lock(this);
		this.refresh()
		return;
	}
	
	this._comboboxListVisible = true;
	
	if (this._selectedItem)
		this._selectedElement.addClass('combobox_item_selected');

	var pos = this._rootElement.offset();
	var elementHeight = this._rootElement.outerHeight();
	var windowHeight = $(window).height();

	var top = pos.top + elementHeight;

	var height = windowHeight - top;
	if (height < pos.top) {
		top -= height + elementHeight;
		height = pos.top;
	}
	
	height -= 10;

	if (height > this._maxHeight)
		height = this._maxHeight;

	if (height < this._minHeight)
		height = this._minHeight

	var itemsHeight = this._comboListElement.height();
	if (height > itemsHeight)
		height = itemsHeight;
	this._comboListElement.attr(
		'style','width: ' + (this.get_width() - 2) + 'px; ' +
				'height: ' + height + 'px;' +
				'left: ' + pos.left + 'px;'+
				'top: ' + top + 'px;'+
				'visibility:visible;');
}

function jQueryNET$Controls$ComboBox$_hideComboList() {
	if (this.get_isLoading())
		return;

	this._comboboxListVisible = false;
	this._comboListElement.removeAttr('style');
}

function jQueryNET$Controls$ComboBox$_showLoadingLayer() {
	var pos = this._rootElement.offset();

	this.set_enabled(false);
	this._rootElement.parent().append(
		'<div unselectable="on" class="loading_layer" style="top:' + pos.top +
		'px; left:' + pos.left +
		'px; height:' + this._rootElement.outerHeight() +
		'px">' + jQueryNET.Resources.Loading + '</div>');

	this._loadingElement = this._rootElement.parent().find('div.loading_layer:last');
}

function jQueryNET$Controls$ComboBox$_hideLoadingLayer() {
	if (this._loadingElement != null)
		this._loadingElement.remove();
	this.set_enabled(true);
}

function jQueryNET$Controls$ComboBox$_completeReceive(data) {
//    debugger;
	this.set_items(data);
}

function jQueryNET$Controls$ComboBox$_onDocumentMouseDown(event) {
	var element = $(event.target);
	
	if (jQueryNET.Utils.Dom.contains(this.get_element(), element.get(0)) ||
		jQueryNET.Utils.Dom.contains(this._comboListElement.get(0), element.get(0)) ) {
		
		if (!this._rootElement.hasClass('focused'))
			this._rootElement.addClass('focused');

		return;
	}

	this._rootElement.removeClass('focused');

	this._hideComboList();
}

function jQueryNET$Controls$ComboBox$_onMouseOver(event, sender) {
	/// <summary>
	/// Mouseover event handler
	/// </summary>

	this._triggerElement.addClass('trigger_over');
}

function jQueryNET$Controls$ComboBox$_onMouseOut(event, sender) {
	/// <summary>
	/// Mouseout event handler
	/// </summary>

	this._triggerElement.removeClass('trigger_over');
}

function jQueryNET$Controls$ComboBox$_onMouseDown(event, sender) {
	/// <summary>
	/// Mousedown event handler
	/// </summary>

	this._triggerElement.addClass('trigger_click');
}

function jQueryNET$Controls$ComboBox$_onMouseUp(event, sender) {
	/// <summary>
	/// Mouseup event handler
	/// </summary>

	this._triggerElement.removeClass('trigger_click');
}

function jQueryNET$Controls$ComboBox$_onMouseClick(event, sender) {
	/// <summary>
	/// Click event handler
	/// </summary>

	//if (this.get_isLoading()) {
		//Function.lock(this);
		//this._comboboxListVisible = true;
	//	return;
	//}
	
	if (this._comboboxListVisible)
		this._hideComboList();
	else
		this._showComboList();
}

function jQueryNET$Controls$ComboBox$_onItemMouseOver(event, sender) {
	if (this._selectedElement && this._selectedElement.hasClass('combobox_item_selected'))
		this._selectedElement.removeClass('combobox_item_selected');

	$(sender).addClass('combobox_item_selected');
}

function jQueryNET$Controls$ComboBox$_onItemMouseOut(event, sender) {
	$(sender).removeClass('combobox_item_selected');
}

function jQueryNET$Controls$ComboBox$_onItemMouseClick(event, sender) {
	this.set_selectedIndex(parseInt(sender.id));
	this._hideComboList();
}

function jQueryNET$Controls$ComboBox$add_selectItemChange(handler) {
	this.get_events().addHandler('selectedItemChange', handler);
}

function jQueryNET$Controls$ComboBox$remove_selectItemChange(handler) {
	this.get_events().removeHandler('selectedItemChange', handler);
}

function jQueryNET$Controls$ComboBox$raiseSelectItemChange(eventArgs) {
	var handler = this.get_events().getHandler('selectedItemChange');
	if (handler) {
		handler(this, eventArgs);
	}
}

jQueryNET.Controls.ComboBox.prototype = {
	_minHeight: 80,
	_maxHeight: 300,
	
	_items: null,
	_selectedItem: null,
	_selectedIndex: -1,
	_selectedValue: null,
	_rootElement: null,
	_inputElement: null,
	_triggerElement: null,
	_comboListElement: null,
	_loadingElement: null,
	_hasItems: true,
	_comboboxListVisible:false,
	_isSelectedIndex: null,
	
	initialize: jQueryNET$Controls$ComboBox$initialize,
	dispose: jQueryNET$Controls$ComboBox$dispose,

	set_theme: jQueryNET$Controls$ComboBox$set_theme,
	get_items: jQueryNET$Controls$ComboBox$get_items,
	set_items: jQueryNET$Controls$ComboBox$set_items,
	get_selectedItem: jQueryNET$Controls$ComboBox$get_selectedItem,
	get_selectedIndex: jQueryNET$Controls$ComboBox$get_selectedIndex,
	set_selectedIndex: jQueryNET$Controls$ComboBox$set_selectedIndex,
	get_selectedValue: jQueryNET$Controls$ComboBox$get_selectedValue,
	set_selectedValue: jQueryNET$Controls$ComboBox$set_selectedValue,
	get_enabled: jQueryNET$Controls$ComboBox$get_enabled,
	set_enabled: jQueryNET$Controls$ComboBox$set_enabled,
	set_width: jQueryNET$Controls$ComboBox$set_width,

	clear: jQueryNET$Controls$ComboBox$clear,
	refresh: jQueryNET$Controls$ComboBox$refresh,
		
	_showComboList: jQueryNET$Controls$ComboBox$_showComboList,
	_hideComboList: jQueryNET$Controls$ComboBox$_hideComboList,
	
	_showLoadingLayer: jQueryNET$Controls$ComboBox$_showLoadingLayer,
	_hideLoadingLayer: jQueryNET$Controls$ComboBox$_hideLoadingLayer,
	_completeReceive: jQueryNET$Controls$ComboBox$_completeReceive,
	
	_onDocumentMouseDown: jQueryNET$Controls$ComboBox$_onDocumentMouseDown,
	
	_onMouseOver: jQueryNET$Controls$ComboBox$_onMouseOver,
	_onMouseOut: jQueryNET$Controls$ComboBox$_onMouseOut,
	_onMouseDown: jQueryNET$Controls$ComboBox$_onMouseDown,
	_onMouseUp: jQueryNET$Controls$ComboBox$_onMouseUp,
	_onMouseClick: jQueryNET$Controls$ComboBox$_onMouseClick,

	_onItemMouseOver: jQueryNET$Controls$ComboBox$_onItemMouseOver,
	_onItemMouseOut: jQueryNET$Controls$ComboBox$_onItemMouseOut,
	_onItemMouseClick: jQueryNET$Controls$ComboBox$_onItemMouseClick,

	add_selectItemChange: jQueryNET$Controls$ComboBox$add_selectItemChange,
	remove_selectItemChange: jQueryNET$Controls$ComboBox$remove_selectItemChange,
	raiseSelectItemChange: jQueryNET$Controls$ComboBox$raiseSelectItemChange
}

jQueryNET.Controls.ComboBox.registerClass("jQueryNET.Controls.ComboBox", jQueryNET.Controls.DataControlBase);